home *** CD-ROM | disk | FTP | other *** search
/ AOL File Library: 2,801 to 2,900 / aol-file-protocol-4400-2801-to-2900.zip / AOLDLs / C++ Files Library / CWASTE C++ text editing routi / CWASTE folder.sit / CWASTE folder / WASTE2.c < prev    next >
Text File  |  1994-07-20  |  29KB  |  1,166 lines

  1. // { WASTE PROJECT: }
  2. // { Unit Two: Creation & Destruction; Getting and Setting Variables &c. }
  3.  
  4. // { Copyright ⌐ 1993-1994 Marco Piovanelli }
  5. // { All Rights Reserved }
  6.  
  7. // C conversion by Dan Crevier
  8.  
  9. #include "WASTEIntf.h"
  10. #include <Palettes.h>
  11. #include <QDOffscreen.h>
  12. #include <GestaltEqu.h>
  13.  
  14. OSErr _WERegisterWithTSM(WEHandle hWE)
  15. {
  16.     // { the WE record must be already locked }
  17.     WEPtr pWE;
  18.     OSType typeList[1];
  19.     OSErr err;
  20.  
  21.     pWE = *hWE;
  22.  
  23.     // { do nothing if the Text Services Manager isn't available }
  24.     if (BTST(pWE->flags, weFHasTextServices))
  25.     {
  26.         typeList[0] = kTextService;
  27.         err = NewTSMDocument(1, typeList, &pWE->tsmReference, (long)hWE);
  28.         if (err != noErr) 
  29.         {
  30.             // { we don't consider it an error if our client application isn't TSM-aware }
  31.             if (err != tsmNeverRegisteredErr) 
  32.             {
  33.                 goto cleanup;
  34.             }
  35.         }
  36.     }
  37.  
  38.     // { clear result code }
  39.     err = noErr;
  40.  
  41. cleanup:
  42.     // { return result code }
  43.     return err;
  44. }
  45.  
  46. pascal void WEStopInlineSession(WEHandle hWE)
  47. {
  48.     TSMDocumentID tsmReference;
  49.  
  50.     tsmReference = (*hWE)->tsmReference;
  51.     if (tsmReference != nil) 
  52.     {
  53.         FixTSMDocument(tsmReference);
  54.     }
  55. }
  56.  
  57. pascal OSErr WENew(LongRect *destRect, LongRect *viewRect, short flags, WEHandle *hWE)
  58. {
  59.     WEPtr pWE;
  60.     short allocFlags;
  61.     long weFlags;
  62.     long response;
  63.     Rect r;
  64.     OSErr err;
  65.     
  66.     pWE = nil;
  67.     weFlags = flags;
  68.     allocFlags = kAllocClear;
  69.  
  70.     // { allocate the WE record }
  71.     err = _WEAllocate(sizeof(WERec), allocFlags, (Handle *)hWE);
  72.     if (err != noErr) 
  73.     {
  74.         goto cleanup;
  75.     }
  76.     
  77.     // { lock it down }
  78.     HLock((Handle)*hWE);
  79.     pWE = **hWE;
  80.  
  81.     // { get active port }
  82.     GetPort(&pWE->port);
  83.  
  84.     // { determine whether temporary memory should be used for data structures }
  85.     if (BTST(weFlags, weFUseTempMem))
  86.     { 
  87.         allocFlags = allocFlags + kAllocTemp;
  88.     }
  89.     
  90.     // { allocate the text handle (initially empty) }
  91.     err = _WEAllocate(0, allocFlags, (Handle *)&pWE->hText);
  92.     if (err != noErr) 
  93.     {
  94.         goto cleanup;
  95.     }
  96.  
  97.     // { allocate the line array }
  98.     err = _WEAllocate(2 * sizeof(LineRec), allocFlags, (Handle *)&pWE->hLines);
  99.     if (err != noErr) 
  100.     {
  101.         goto cleanup;
  102.     }
  103.  
  104.     // { allocate the style table }
  105.     err = _WEAllocate(sizeof(StyleTableElement), allocFlags, (Handle *)&pWE->hStyles);
  106.     if (err != noErr) 
  107.     {
  108.         goto cleanup;
  109.     }
  110.     
  111.     // { allocate the run array }
  112.     err = _WEAllocate(2 * sizeof(RunArrayElement), allocFlags, (Handle *)&pWE->hRuns);
  113.     if (err != noErr) 
  114.     {
  115.         goto cleanup;
  116.     }
  117.     
  118.     // { check for the presence of various system software features }
  119.     // { determine whether Color QuickDraw is available }
  120.     if (Gestalt(gestaltQuickdrawVersion, &response) == noErr) 
  121.     {
  122.         if (response >= gestalt8BitQD)
  123.         { 
  124.             BSET(weFlags, weFHasColorQD);
  125.         }
  126.     }
  127.     
  128.     // { determine whether the Text Services manager is available }
  129.     if (Gestalt(gestaltTSMgrVersion, &response) == noErr)
  130.     { 
  131.         BSET(weFlags, weFHasTextServices);
  132.     }
  133.     
  134.     // { determine if there are any non-Roman scripts enabled }
  135.     if (GetEnvirons(smEnabled) > 1) 
  136.     {
  137.         BSET(weFlags, weFNonRoman);
  138.     }
  139.     
  140.     // { determine whether a double-byte script is installed }
  141.     if (GetEnvirons(smDoubleByte) != 0) 
  142.     {
  143.         BSET(weFlags, weFDoubleByte);
  144.     }
  145.     
  146.     // { initialize miscellaneous fields of the WE record }
  147.     pWE->nLines = 1;
  148.     pWE->nStyles = 1;
  149.     pWE->nRuns = 1;
  150.     pWE->viewRect = *viewRect;
  151.     pWE->destRect = *destRect;
  152.     pWE->flags = weFlags;
  153.     pWE->tsmAreaStart = kInvalidOffset;
  154.     pWE->tsmAreaEnd = kInvalidOffset;
  155.  
  156.     // { create a region to hold the view rectangle }
  157.     pWE->viewRgn = NewRgn();
  158.     WELongRectToRect(viewRect, &r);
  159.     RectRgn(pWE->viewRgn, &r);
  160.  
  161.     // { initialize the style run array }
  162.     (*pWE->hRuns)[1].runStart = 1;
  163.     (*pWE->hRuns)[1].styleIndex = -1;
  164.  
  165.     // { initialize the style table }
  166.     (*pWE->hStyles)[0].refCount = 1;
  167.  
  168.     // { copy text attributes from the active graphics port }
  169.     (*pWE->hStyles)[0].info.runStyle.tsFont = pWE->port->txFont;
  170.     (*pWE->hStyles)[0].info.runStyle.tsSize = pWE->port->txSize;
  171.     (*pWE->hStyles)[0].info.runStyle.tsFace = ((GrafPtr1)pWE->port)->txFace;
  172.     _WEFillFontInfo(pWE->port, &(*pWE->hStyles)[0].info);
  173.     if (BTST(weFlags, weFHasColorQD))
  174.     { 
  175.         GetForeColor(&(*pWE->hStyles)[0].info.runStyle.tsColor);
  176.     }
  177.  
  178.     // { initialize the line array }
  179.     err = WECalText(*hWE);
  180.     if (err != noErr) 
  181.     {
  182.         goto cleanup;
  183.     }
  184.     
  185.     // { register with the Text Services Manager }
  186.     err = _WERegisterWithTSM(*hWE);
  187.     if (err != noErr) 
  188.     {
  189.         goto cleanup;
  190.     }
  191.  
  192.     // { unlock the WE record }
  193.     HUnlock((Handle)*hWE);
  194.  
  195.     // { skip clean-up section }
  196.     return noErr;
  197.  
  198. cleanup:
  199.     // { clean up }
  200.     if (pWE != nil) 
  201.     {
  202.         _WEForgetHandle((Handle *)&pWE->hText);
  203.         _WEForgetHandle((Handle *)&pWE->hLines);
  204.         _WEForgetHandle((Handle *)&pWE->hStyles);
  205.         _WEForgetHandle((Handle *)&pWE->hRuns);
  206.         if (pWE->viewRgn != nil) 
  207.         {
  208.             DisposeRgn(pWE->viewRgn);
  209.         }
  210.     }
  211.     _WEForgetHandle((Handle *)hWE);
  212.  
  213.     return err;
  214. }
  215.  
  216. pascal void WEDispose(WEHandle hWE)
  217. {
  218.     WEPtr pWE;
  219.  
  220.     // { sanity check: make sure WE isn't NIL }
  221.     if (hWE == nil)
  222.     {
  223.         return;
  224.     } 
  225.  
  226.     // { lock the WE record }
  227.     HLock((Handle)hWE);
  228.     pWE = *hWE;
  229.  
  230.     // { dispose of auxiliary data structures }
  231.     _WEForgetHandle((Handle *)&pWE->hText);
  232.     _WEForgetHandle((Handle *)&pWE->hLines);
  233.     _WEForgetHandle((Handle *)&pWE->hStyles);
  234.     _WEForgetHandle((Handle *)&pWE->hRuns);
  235.     DisposeRgn(pWE->viewRgn);
  236.  
  237.     // { dispose of the offscreen graphics world }
  238.     if (pWE->offscreenPort != nil) 
  239.     {
  240.         DisposeGWorld((GWorldPtr)pWE->offscreenPort);
  241.     }
  242.     
  243.     // { unregister with the Text Services Manager }
  244.     if (pWE->tsmReference != nil) 
  245.     {
  246.         DeleteTSMDocument(pWE->tsmReference);
  247.     }
  248.  
  249.     // { dispose of the WE record }
  250.     DisposeHandle((Handle)hWE);
  251. }
  252.  
  253. OSErr _WERemoveLine(long lineIndex, WEPtr pWE)
  254. {
  255.     OSErr retval;
  256.     
  257.     // { remove the specified element from the line array }
  258.  
  259.     // { do the removal (errors returned by _WERemoveSlot can be safely ignored) }
  260.     retval = _WERemoveSlot((Handle)pWE->hLines, lineIndex, sizeof(LineRec));
  261.  
  262.     // { decrement line count }
  263.     pWE->nLines = pWE->nLines - 1;
  264.     
  265.     return retval;
  266. }
  267.  
  268. OSErr InsertLine(long lineIndex, LineRec *theLine, WEPtr pWE)
  269. {
  270.     // { insert the specified element in the line array }
  271.  
  272.     OSErr err;
  273.  
  274.     // { do the insertion }
  275.     err = _WEInsertSlot((Handle)pWE->hLines, (Ptr)theLine, lineIndex, sizeof(LineRec));
  276.     if (err != noErr) 
  277.     {
  278.         return err;
  279.     }
  280.  
  281.     // { increment line count }
  282.     pWE->nLines = pWE->nLines + 1;
  283.  
  284.     return noErr;
  285. }
  286.  
  287. void _WEBumpOrigin(long lineIndex, long deltaOrigin, WEPtr pWE)
  288. {
  289.     long *pOrigin;
  290.     long nLines;
  291.  
  292.     pOrigin = &((*pWE->hLines)[lineIndex].lineOrigin);
  293.  
  294.     // { loop through the line run array adjusting the lineOrigin fields }
  295.     nLines = pWE->nLines;
  296.     while (lineIndex <= nLines)
  297.     {
  298.         *pOrigin = *pOrigin + deltaOrigin;
  299.         pOrigin = (long *)((long)pOrigin + sizeof(LineRec));
  300.         lineIndex = lineIndex + 1;
  301.     }
  302. }
  303.  
  304. long _WEFindLineBreak(long lineStart, WEHandle hWE)
  305. {
  306.     // { Find where to break the line beginning at lineStart }
  307.     // { the WE record and the text must be already locked }
  308.     // { the current graphics port must be already set up correctly }
  309.  
  310.     WEPtr pWE;
  311.     Ptr pText;
  312.     long offset, breakOffset;
  313.     long textLength;
  314.     long remainingLength;
  315.     long segmentStart, segmentEnd;
  316.     long runIndex;
  317.     WERunInfo runInfo;
  318.     Fixed pixelWidth;
  319.     ScriptCode script, previousScript;
  320.  
  321.     pWE = *hWE;
  322.     offset = lineStart;
  323.     pText = *pWE->hText + offset;
  324.     remainingLength = pWE->textLength - offset;
  325.  
  326.     // { find the style run index corresponding to the first segment on this line }
  327.     runIndex = _WEOffsetToRun(offset, hWE);
  328.  
  329.     // { initialize pixelWidth to the width of the destination rectangle, as a Fixed quantity }
  330.     pixelWidth = BSL(pWE->destRect.right - pWE->destRect.left, 16);
  331.  
  332.     // { STYLE SEGMENT LOOP }
  333.     do
  334.     {
  335.  
  336.         // { get style run information for the current style run }
  337.         _WEGetIndStyle(runIndex, &runInfo, hWE);
  338.         runIndex = runIndex + 1;
  339.  
  340.         // { set text attributes in the graphics port }
  341.         TextFont(runInfo.runAttrs.runStyle.tsFont);
  342.         TextFace(runInfo.runAttrs.runStyle.tsFace);
  343.         TextSize(runInfo.runAttrs.runStyle.tsSize);
  344.  
  345.         // { if we're handling multiscript text, keep track of script boundaries }
  346.         if (BTST(pWE->flags, weFNonRoman))
  347.         { 
  348.             // { what is the script for this segment? }
  349.             script = Font2Script(runInfo.runAttrs.runStyle.tsFont);
  350.  
  351.             // { have we crossed a script run boundary in the middle of a line? }
  352.             if ((runInfo.runStart > offset) && (script != previousScript))
  353.             {
  354.                 // { leave behind the all previous segments on this line }
  355.                 offset = runInfo.runStart;
  356.                 pText = *pWE->hText + offset;
  357.                 remainingLength = pWE->textLength - offset;
  358.             }
  359.             previousScript = script;
  360.         } // { if non-Roman }
  361.  
  362.         // { we'll pass textLength as the second parameter to StyledLineBreak }
  363.         // { although this parameter is declared as a long, StyledLineBreak uses only }
  364.         // { the low word, so make sure it doesn't trespass the 32,767 byte threshold! }
  365.         textLength = _WEPinInRange(remainingLength, 0, SHRT_MAX);
  366.  
  367.         // { calculate segmentStart and segmentEnd relative to offset }
  368.         segmentStart = _WEPinInRange(runInfo.runStart - offset, 0, textLength);
  369.         segmentEnd = _WEPinInRange(runInfo.runEnd - offset, 0, textLength);
  370.  
  371.         // { set breakOffset to a non-zero value for the first script run on the line, }
  372.         // { set it to zero for all subsequent script runs }
  373.         breakOffset = (offset == lineStart);
  374.  
  375.         // { keep looping until StyledLineBreak detects a break or we reach the end of the text }
  376.     } while ((StyledLineBreak(pText, textLength, segmentStart, segmentEnd, 0, &pixelWidth, &breakOffset)
  377.              == smBreakOverflow) && (segmentEnd < remainingLength));
  378.  
  379.     // { return the offset from lineStart to the break point }
  380.     return (offset - lineStart) + breakOffset;
  381. }
  382.  
  383. void _WECalcHeights(long rangeStart, long rangeEnd, short *lineAscent, short *lineDescent,
  384.         WEHandle hWE)
  385. {
  386.     // { Find the maximum ascent and descent values between rangeStart and rangeEnd }
  387.     // { the WE record must be already locked }
  388.     // { the current graphics port must be already set up correctly }
  389.  
  390.     long runIndex;
  391.     WERunInfo runInfo;
  392.     short runAscent, runDescent;
  393.  
  394.     *lineAscent = 1;
  395.     *lineDescent = 1;
  396.  
  397.     // { find the style run index corresponding to the first segment on this line }
  398.     runIndex = _WEOffsetToRun(rangeStart, hWE);
  399.  
  400.     // { STYLE SEGMENT LOOP }
  401.     do
  402.     {
  403.         // { get style run information for the current style run }
  404.         _WEGetIndStyle(runIndex, &runInfo, hWE);
  405.         runIndex = runIndex + 1;
  406.  
  407.         // { calculate ascent and descent (actually, descent + leading) values for this style run }
  408.         runAscent = runInfo.runAttrs.runAscent;
  409.         runDescent = runInfo.runAttrs.runHeight - runAscent;
  410.  
  411.         // { save the maximum values in lineAscent and lineDescent }
  412.         if (runAscent > *lineAscent) 
  413.         {
  414.             *lineAscent = runAscent;
  415.         }
  416.         if (runDescent > *lineDescent) 
  417.         {
  418.             *lineDescent = runDescent;
  419.         }
  420.         
  421.         // { keep looping until we reach rangeEnd }
  422.     } while (runInfo.runEnd < rangeEnd);
  423. }
  424.  
  425. OSErr _WERecalBreaks(long *startLine, long *endLine, WEHandle hWE)
  426. {
  427.     // { Recalculates line breaks, line heights and ascents for all the text or for a portion of it. }
  428.     // { On entry, startLine and endLine define a range of lines to recalculate. }
  429.     // { On exit, startLine to endLine defines the range of lines actually recalculated }
  430.     // { the WE record must already be locked }
  431.  
  432.     WEPtr pWE;
  433.     LinePtr pLine;
  434.     LineRec lineInfo, oldLineInfo;
  435.     long lineIndex;
  436.     long recalThreshold;
  437.     long lineOffset;
  438.     short lineAscent, lineDescent;
  439.     Boolean saveTextLock;
  440.     QDEnvironment saveEnvironment;
  441.     OSErr err;
  442.     OSErr retval;
  443.  
  444.     retval = noErr;
  445.     pWE = *hWE;
  446.  
  447.     // { lock the text }
  448.     saveTextLock = _WESetHandleLock(pWE->hText, true);
  449.  
  450.     // { find the character offset that must be necessarily reached before we can }
  451.     // { even consider the possibility of stopping the recalculation process }
  452.     // { this offset, recalThreshold, is the last character on endLine _before_ recalculation }
  453.     lineIndex = _WEPinInRange(*endLine, 0, pWE->nLines - 1);
  454.     recalThreshold = (*pWE->hLines)[lineIndex + 1].lineStart;
  455.  
  456.     // { we start recalculating line breaks from the line actually _preceding_ startLine, }
  457.     // { since editing startLine may cause part of its text to fit on the preceding line }
  458.     lineIndex = _WEPinInRange(*startLine - 1, 0, pWE->nLines - 1);
  459.  
  460.     // { find where in the text recalculation should begin }
  461.     lineInfo = (*pWE->hLines)[lineIndex];
  462.  
  463.     // { save the QuickDraw environment }
  464.     _WESaveQDEnvironment(pWE->port, false, &saveEnvironment);
  465.  
  466.     // { MAIN LINE BREAKING LOOP }
  467.     do
  468.     {
  469.         // { find where to break the current line }
  470.         lineOffset = _WEFindLineBreak(lineInfo.lineStart, hWE);
  471.  
  472.         // { calculate ascent and descent values for this line }
  473.         _WECalcHeights(lineInfo.lineStart, lineInfo.lineStart + lineOffset, &lineAscent, &lineDescent, hWE);
  474.  
  475.         // { save the maximum line ascent for this line in the line array }
  476.         pLine = &(*pWE->hLines)[lineIndex];
  477.         pLine->lineAscent = lineAscent;
  478.  
  479.         // { increment counters (go to the next line array entry) }
  480.         lineIndex = lineIndex + 1;
  481.         lineInfo.lineStart = lineInfo.lineStart + lineOffset;
  482.         lineInfo.lineOrigin = lineInfo.lineOrigin + (lineAscent + lineDescent);
  483.         pLine++;
  484.         
  485.         // { compare the newly calculated line start with the old value }
  486.         // { if the new line start comes before the old line start, insert a new element }
  487.         oldLineInfo = *pLine;
  488.         if ((lineIndex > pWE->nLines) || (lineInfo.lineStart < oldLineInfo.lineStart)) 
  489.         {
  490.             err = InsertLine(lineIndex, &lineInfo, pWE);
  491.  
  492.             // { clean up and exit if we ran out of memory }
  493.             if (err != noErr) 
  494.             {
  495.                 retval = err;
  496.                 goto cleanup;
  497.             }
  498.         }
  499.         else
  500.         {
  501.             // { overwrite the old element }
  502.             pLine->lineStart = lineInfo.lineStart;
  503.             pLine->lineOrigin = lineInfo.lineOrigin;
  504.  
  505.             // { remove all further elements which have a lineStart field }
  506.             // { less than or equal to the current one }
  507.             while((lineIndex + 1 <= pWE->nLines) && 
  508.                 (lineInfo.lineStart >= (*pWE->hLines)[lineIndex + 1].lineStart))
  509.             {
  510.                 err = _WERemoveLine(lineIndex + 1, pWE);
  511.             }
  512.  
  513.             // { if the new line start is the same as the old one... }
  514.             if (lineInfo.lineStart == oldLineInfo.lineStart) 
  515.             {
  516.                 // { ...and recalThreshold has been reached, we can stop recalculating line breaks }
  517.                 if (lineInfo.lineStart >= recalThreshold) 
  518.                 {
  519.                     // { although line breaks need not be changed from lineIndex on, }
  520.                     // { the lineOrigin fields may need to be changed }
  521.                     if (lineInfo.lineOrigin != oldLineInfo.lineOrigin) 
  522.                     {
  523.                         _WEBumpOrigin(lineIndex + 1, lineInfo.lineOrigin - oldLineInfo.lineOrigin, pWE);
  524.                     }
  525.                     
  526.                     // { exit from the line breaking loop }
  527.                     goto cleanup;
  528.                 }
  529.             }
  530.             else
  531.             {
  532.                 // { otherwise, the new line start comes after the old line start... }
  533.                 // { if the current line is the one preceding startLine, warn our caller about this }
  534.                 if ((lineIndex > 0) && (lineIndex == *startLine)) 
  535.                 {
  536.                     *startLine = lineIndex - 1;
  537.                 }
  538.             }
  539.         }
  540.     } while(lineInfo.lineStart < pWE->textLength);
  541.  
  542. cleanup:
  543.     // { set destRect.bottom to destRect.top + total text height }
  544.     pWE->destRect.bottom = pWE->destRect.top + WEGetHeight(0, pWE->nLines, hWE);
  545.  
  546.     // { quirk: if the last character in the text is a carriage return, the caret appears }
  547.     // { below the last line, so in this case we need to add the extra height to destRect.bottom }
  548.     if (WEGetChar(pWE->textLength - 1, hWE) == '\r')
  549.     {
  550.         pWE->destRect.bottom = pWE->destRect.bottom + 
  551.                                     WEGetHeight(pWE->nLines - 1, pWE->nLines, hWE);
  552.     }
  553.     
  554.     // { return through endLine the index of the last line affected by recalculation }
  555.     *endLine = lineIndex - 1;
  556.  
  557.     // { make sure startLine isn't greater than endLine }
  558.     if (*startLine > *endLine) 
  559.     {
  560.         *startLine = *endLine;
  561.     }
  562.     
  563.     // { unlock the text }
  564.     _WESetHandleLock(pWE->hText, saveTextLock);
  565.  
  566.     // { restore the QuickDraw environment }
  567.     _WERestoreQDEnvironment(&saveEnvironment);
  568.     return retval;
  569. }
  570.  
  571. Boolean SLCalcSlop(LinePtr pLine, WERunAttributesPtr pAttrs, Ptr pSegment, long segmentStart,
  572.     long segmentLength, JustStyleCode styleRunPosition, void *callbackData);
  573.  
  574.  
  575. Boolean SLCalcSlop(LinePtr pLine, WERunAttributesPtr pAttrs, Ptr pSegment, long segmentStart,
  576.     long segmentLength, JustStyleCode styleRunPosition, void *callbackData)
  577. {
  578.     Boolean isEndOfLine;
  579.     Boolean retval;
  580.     struct SLCalcSlopData *p = (struct SLCalcSlopData *) callbackData;
  581.  
  582.     retval = false;                // { keep looping }
  583.  
  584.     // { see if this text segment ends with a carriage return, or if we've reached the }
  585.     // { end of the text (in which case we don't want any justification to take place) }
  586.     isEndOfLine = (segmentStart + segmentLength >= p->pWE->textLength) ||
  587.                     ( *((Ptr)pSegment + segmentLength - 1) == kEOL);
  588.  
  589.     // { if this is the first segment on the line, reset line totals }
  590.     if (styleRunPosition <= smLeftStyleRun) 
  591.     {
  592.         p->totalSlop = p->lineWidth;
  593.         p->totalProportion = 0;
  594.     }
  595.  
  596.     // { if this is the last segment on the line, strip trailing spaces }
  597.     if (!(styleRunPosition & 1)) 
  598.     {
  599.         segmentLength = VisibleLength(pSegment, segmentLength);
  600.     }
  601.  
  602.     // { measure this segment and subtract its width from totalSlop }
  603.     p->totalSlop = p->totalSlop - TextWidth(pSegment, 0, segmentLength);
  604.  
  605.     // { calculate the proportion of extra space to apply to this text segment }
  606.     p->totalProportion = p->totalProportion + NPortionText(pSegment, segmentLength,
  607.             styleRunPosition, *(Point *)&kOneToOneScaling, *(Point *)&kOneToOneScaling);
  608.  
  609.     // { if this is the last segment on the line, save values in the line array }
  610.     if (!(styleRunPosition & 1)) 
  611.     {
  612.         pLine->lineSlop = p->totalSlop;
  613.         if (isEndOfLine) 
  614.         {
  615.             pLine->lineJustAmount = 0;
  616.         }
  617.         else
  618.         {
  619.                 pLine->lineJustAmount = FixDiv(BSL(p->totalSlop, 16), p->totalProportion);
  620.         }
  621.     }
  622.     return retval;
  623. }
  624.  
  625.  
  626. void _WERecalSlops(long firstLine, long lastLine, WEHandle hWE)
  627. {
  628.     // { Calculates the lineSlop and lineJustAmount fields }
  629.     // { of the line array for the specified lines }
  630.  
  631.     WEPtr pWE;
  632.     short lineWidth;
  633.     struct SLCalcSlopData callbackData;
  634.  
  635.     pWE = *hWE;
  636.     lineWidth = pWE->destRect.right - pWE->destRect.left;
  637.  
  638.     // { calculate slop and normalized slop proportion for all lines }
  639.     callbackData.lineWidth = lineWidth;
  640.     callbackData.pWE = pWE;
  641.     _WESegmentLoop(firstLine, lastLine, SLCalcSlop, (void *) &callbackData, hWE);
  642. }
  643.  
  644. pascal OSErr WECalText(WEHandle hWE)
  645. {
  646.     long startLine, endLine;
  647.     Boolean saveWELock;
  648.     OSErr err;
  649.  
  650.     // { lock WE record }
  651.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  652.  
  653.     // { recalculate all line breaks }
  654.     startLine = 0;
  655.     endLine = LONG_MAX;
  656.     err = _WERecalBreaks(&startLine, &endLine, hWE);
  657.  
  658.     // { recalculate line slops }
  659.     if (err == noErr) 
  660.     {
  661.         _WERecalSlops(startLine, endLine, hWE);
  662.     }
  663.  
  664.     // { unlock the WE record }
  665.     _WESetHandleLock((Handle)hWE, saveWELock);
  666.  
  667.     // { return result code }
  668.     return err;
  669. }
  670.  
  671. pascal OSErr WEUseText(Handle text, WEHandle hWE)
  672. {
  673.     WEPtr pWE;
  674.     long textLength;
  675.     Boolean saveWELock;
  676.  
  677.     // { lock the WE record }
  678.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  679.     pWE = *hWE;
  680.  
  681.     // { install the text }
  682.     _WEForgetHandle((Handle *)&pWE->hText);
  683.     pWE->hText = text;
  684.     textLength = GetHandleSize(text);
  685.     pWE->textLength = textLength;
  686.     (*pWE->hRuns)[pWE->nRuns].runStart = textLength + 1;
  687.     (*pWE->hLines)[pWE->nLines].lineStart = textLength;
  688.  
  689.     // { unlock the WE record }
  690.     _WESetHandleLock((Handle)hWE, saveWELock);
  691.  
  692.     return noErr;
  693. }
  694.  
  695. pascal char WEGetAlignment(WEHandle hWE)
  696. {
  697.     return (*hWE)->alignment;
  698. }
  699.  
  700. pascal void WEGetSelection(long *selStart, long *selEnd, WEHandle hWE)
  701. {
  702.     WEPtr pWE;
  703.  
  704.     pWE = *hWE;
  705.     *selStart = pWE->selStart;
  706.     *selEnd = pWE->selEnd;
  707. }
  708.  
  709. pascal void WESetDestRect(LongRect *destRect, WEHandle hWE)
  710. {
  711.     (*hWE)->destRect = *destRect;
  712. }
  713.  
  714. pascal void WEGetDestRect(LongRect *destRect, WEHandle hWE)
  715. {
  716.     *destRect = (*hWE)->destRect;
  717. }
  718.  
  719. pascal void WESetViewRect(LongRect *viewRect, WEHandle hWE)
  720. {
  721.     WEPtr pWE;
  722.     Rect r;
  723.     
  724.     pWE = *hWE;
  725.     pWE->viewRect = *viewRect;
  726.  
  727.     // { keep the viewRgn in sync with the view rectangle }
  728.     WELongRectToRect(viewRect, &r);
  729.     RectRgn(pWE->viewRgn, &r);
  730. }
  731.  
  732. pascal void WEGetViewRect(LongRect *viewRect, WEHandle hWE)
  733. {
  734.     *viewRect = (*hWE)->viewRect;
  735. }
  736.  
  737. pascal long WEGetTextLength(WEHandle hWE)
  738. {
  739.     return (*hWE)->textLength;
  740. }
  741.  
  742. pascal long WECountLines(WEHandle hWE)
  743. {
  744.     return (*hWE)->nLines;
  745. }
  746.  
  747. pascal long WEGetHeight(long startLine, long endLine, WEHandle hWE)
  748. {
  749.     WEPtr pWE;
  750.     LineArrayPtr pLines;
  751.     long nLines;
  752.  
  753.     pWE = *hWE;
  754.     pLines = *pWE->hLines;
  755.     nLines = pWE->nLines;
  756.     startLine = _WEPinInRange(startLine, 0, nLines);
  757.     endLine = _WEPinInRange(endLine, 0, nLines);
  758.     _WEReorder(&startLine, &endLine);
  759.     return pLines[endLine].lineOrigin - pLines[startLine].lineOrigin;
  760. }
  761.  
  762. pascal Handle WEGetText(WEHandle hWE)
  763. {
  764.     return (*hWE)->hText;
  765. }
  766.  
  767. pascal char WEGetChar(long offset, WEHandle hWE)
  768. {
  769.     WEPtr pWE;
  770.  
  771.     pWE = *hWE;
  772.  
  773.     // { sanity check: make sure offset is withing allowed bounds }
  774.     if ((offset < 0) || (offset >= pWE->textLength))
  775.     {
  776.         return 0;
  777.     }
  778.  
  779.     // { get the specified character (actually, byte) }
  780.     return (*pWE->hText)[offset];
  781. }
  782.  
  783. pascal short WECharByte(long offset, WEHandle hWE)
  784. {
  785.     WEPtr pWE;
  786.     WERunInfo info;
  787.     short saveFont;
  788.     GrafPtr savePort;
  789.     short byte;
  790.  
  791.     pWE = *hWE;
  792.  
  793.     // { exit now if there is no double-byte script system installed }
  794.     if (!BTST(pWE->flags, weFDoubleByte)) 
  795.     {
  796.         return smSingleByte;
  797.     }
  798.  
  799.     // { sanity check: make sure offset is within allowed bounds }
  800.     if ((offset < 0) || (offset >= pWE->textLength)) 
  801.     {
  802.         return smSingleByte;
  803.     }
  804.  
  805.     // { get style information associated with the specified offset }
  806.     WEGetRunInfo(offset, &info, hWE);
  807.  
  808.     // { save the port }
  809.     GetPort(&savePort);
  810.     SetPort(pWE->port);
  811.  
  812.     // { set the port font to the style run font }
  813.     saveFont = pWE->port->txFont;
  814.     TextFont(info.runAttrs.runStyle.tsFont);
  815.  
  816.     // { pass CharByte a pointer to the beginning of the style run }
  817.     byte = CharByte((Ptr)(*pWE->hText) + info.runStart, offset - info.runStart);
  818.  
  819.     // { restore the port font }
  820.     TextFont(saveFont);
  821.  
  822.     // { restore the port }
  823.     SetPort(savePort);
  824.     
  825.     return byte;
  826. }
  827.  
  828. pascal short WECharType(long offset, WEHandle hWE)
  829. {
  830.     WEPtr pWE;
  831.     WERunInfo info;
  832.     Handle hText;
  833.     short saveFont;
  834.     GrafPtr savePort;
  835.     Boolean saveTextLock;
  836.     short retval;
  837.     
  838.     pWE = *hWE;
  839.     hText = pWE->hText;
  840.  
  841.     // { sanity check: make sure offset is within allowed bounds }
  842.     if ((offset < 0) || (offset >= pWE->textLength)) 
  843.     {
  844.         return 0;
  845.     }
  846.  
  847.     // { get style information associated with the specified offset }
  848.     WEGetRunInfo(offset, &info, hWE);
  849.  
  850.     // { save the port }
  851.     GetPort(&savePort);
  852.     SetPort(pWE->port);
  853.  
  854.     // { set the port font to the style run font }
  855.     saveFont = pWE->port->txFont;
  856.     TextFont(info.runAttrs.runStyle.tsFont);
  857.  
  858.     // { lock the text (CharType may move memory) }
  859.     saveTextLock = _WESetHandleLock(hText, true);
  860.  
  861.     // { pass CharType a pointer to the beginning of the style run }
  862.     retval = CharType((Ptr)*pWE->hText + info.runStart, offset - info.runStart);
  863.  
  864.     // { unlock the text }
  865.     _WESetHandleLock(hText, saveTextLock);
  866.  
  867.     // { restore the port font }
  868.     TextFont(saveFont);
  869.  
  870.     // { restore the port }
  871.     SetPort(savePort);
  872.     
  873.     return retval;
  874. }
  875.  
  876. pascal OSErr WECopyRange(long rangeStart, long rangeEnd, Handle hText, WEStyleScrapHandle
  877.                     hStyles, WEHandle hWE)
  878. {
  879.  
  880.     // { Make a copy of the specified range of text: store the characters in hText }
  881.     // { and the associated style scrap in hStyles.  The handles are resized as necessary. }
  882.     // { Specify NIL in hText or hStyles if you don't want the corresponding info returned. }
  883.  
  884.     WEPtr pWE;
  885.     long rangeLength;
  886.     long firstRun, nRuns, i;
  887.     long startChar;
  888.     WERunInfo info;
  889.     WEStyleScrapElementPtr pElement;
  890.     Boolean saveWELock;
  891.     OSErr err;
  892.  
  893.     // { lock the WE record }
  894.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  895.     pWE = *hWE;
  896.  
  897.     // { range-check parameters and reorder them if necessary }
  898.     rangeStart = _WEPinInRange(rangeStart, 0, pWE->textLength);
  899.     rangeEnd = _WEPinInRange(rangeEnd, 0, pWE->textLength);
  900.     _WEReorder(&rangeStart, &rangeEnd);
  901.     rangeLength = rangeEnd - rangeStart;
  902.  
  903.     if (hText != nil) 
  904.     {
  905.         // { resize the given handle }
  906.         SetHandleSize(hText, rangeLength);
  907.         err = MemError();
  908.         if (err != noErr) 
  909.         {
  910.             goto cleanup;
  911.         }
  912.  
  913.         // { copy the text range }
  914.         BlockMoveData((Ptr)*pWE->hText + rangeStart, (Ptr)*hText, rangeLength);
  915.  
  916.     }
  917.  
  918.     if (hStyles != nil) 
  919.     {
  920.         // { count how many style runs there are in the selection range }
  921.         firstRun = _WEOffsetToRun(rangeStart, hWE);
  922.         nRuns = _WEOffsetToRun(rangeEnd - 1, hWE) - firstRun + 1;
  923.  
  924.         // { try to allocate a handle big enough to contain all these style runs }
  925.         // { resize the given handle }
  926.         SetHandleSize((Handle)hStyles, sizeof(short) + (nRuns * sizeof(ScrpSTElement)));
  927.         err = MemError();
  928.         if (err != noErr)
  929.         {
  930.             goto cleanup;
  931.         }
  932.  
  933.         // { fill in the style count in the style scrap }
  934.         // { *** POTENTIAL PROBLEM: if nRuns > 32767, scrpNStyles will be invalid *** }
  935.         (*hStyles)->scrpNStyles = nRuns;
  936.  
  937.         // { fill the style scrap }
  938.         pElement = &(*hStyles)->scrpStyleTab[0];
  939.         for(i = 0; i<nRuns; i++)
  940.         {
  941.             _WEGetIndStyle(firstRun + i, &info, hWE);
  942.             startChar = info.runStart - rangeStart;
  943.             if (startChar < 0)
  944.             {
  945.                 startChar = 0;
  946.             }
  947.             pElement->scrpStartChar = startChar;
  948.             pElement->scrpAttrs = info.runAttrs;
  949.             pElement->scrpAttrs.runStyle.tsFlags = 0;
  950.             pElement++;
  951.         }
  952.     }
  953.     // { clear result code }
  954.     err = noErr;
  955.  
  956. cleanup:
  957.     
  958.     // { unlock the WE record }
  959.     _WESetHandleLock((Handle)hWE, saveWELock);
  960.     // { return result code }
  961.     return err;
  962. }
  963.  
  964. pascal OSErr WECopy(WEHandle hWE)
  965. {
  966.     // { Copy the selection range to the desk scrap }
  967.  
  968.     WEPtr pWE;
  969.     long selStart, selEnd;
  970.     Handle hText, hStyles;
  971.     OSErr err;
  972.  
  973.     pWE = *hWE;
  974.     hText = nil;
  975.     hStyles = nil;
  976.  
  977.     // { get selection range }
  978.     selStart = pWE->selStart;
  979.     selEnd = pWE->selEnd;
  980.  
  981.     // { do nothing if the selection range is empty }
  982.     if (selStart < selEnd) 
  983.     {
  984.         // { allocate two zero-length handles to hold a copy of the selection text and styles }
  985.         err = _WEAllocate(0, kAllocTemp, (Handle *)&hText);
  986.         if (err != noErr) 
  987.         {
  988.             goto cleanup;
  989.         }
  990.  
  991.         err = _WEAllocate(0, kAllocTemp, (Handle *)&hStyles);
  992.         if (err != noErr) 
  993.         {
  994.             goto cleanup;
  995.         }
  996.  
  997.         // { make a copy of the selection text and styles }
  998.         err = WECopyRange(selStart, selEnd, hText, (WEStyleScrapHandle)hStyles, hWE);
  999.         if (err != noErr) 
  1000.         {
  1001.             goto cleanup;
  1002.         }
  1003.         
  1004.         // { clear the desk scrap }
  1005.         err = ZeroScrap();
  1006.         if (err != noErr) 
  1007.         {
  1008.             goto cleanup;
  1009.         }
  1010.         
  1011.         // { put the text }
  1012.         HLock(hText);
  1013.         err = PutScrap(GetHandleSize(hText), kTypeText, *hText);
  1014.         if (err != noErr)
  1015.         {
  1016.             goto cleanup;
  1017.         }
  1018.         HUnlock(hText);
  1019.  
  1020.         // { put the styles }
  1021.         HLock(hStyles);
  1022.         err = PutScrap(GetHandleSize(hStyles), kTypeStyles, *hStyles);
  1023.         if (err != noErr)
  1024.         {
  1025.             goto cleanup;
  1026.         }
  1027.         HUnlock(hStyles);
  1028.     }
  1029.     // { clear result code }
  1030.     err = noErr;
  1031.  
  1032. cleanup:
  1033.     // { clean up }
  1034.     _WEForgetHandle((Handle *)&hText);
  1035.     _WEForgetHandle((Handle *)&hStyles);
  1036.  
  1037.     // { return result code }
  1038.     return err;
  1039. }
  1040.  
  1041. pascal short WEFeatureFlag(short feature, short action, WEHandle hWE)
  1042. {
  1043.     WEPtr pWE;
  1044.     short retval;
  1045.     
  1046.     pWE = *hWE;
  1047.  
  1048.     // { return current status }
  1049.     retval = BTST(pWE->flags, feature) ? weBitSet : weBitClear;
  1050.  
  1051.     // { set new status if necessary }
  1052.     if (action == weBitClear)
  1053.     { 
  1054.         BCLR(pWE->flags, feature);
  1055.     }
  1056.     else if (action == weBitSet)
  1057.     { 
  1058.         BSET(pWE->flags, feature);
  1059.     }
  1060.     
  1061.     return retval;
  1062. }
  1063.  
  1064. pascal OSErr WEGetInfo(OSType selector, Ptr info, WEHandle hWE)
  1065. {
  1066.     switch(selector)
  1067.     {
  1068.         case 'clik':
  1069.             *(long *)info = (long)(*hWE)->clickLoop;
  1070.             return noErr;
  1071.         
  1072.         case 'line':
  1073.             *(long *)info = (long)(*hWE)->hLines;
  1074.             return noErr;
  1075.             
  1076.         case 'port':
  1077.             *(long *)info = (long)(*hWE)->port;
  1078.             return noErr;
  1079.         
  1080.         case 'post':
  1081.             *(long *)info = (long)(*hWE)->tsmPostUpdate;
  1082.             return noErr;
  1083.         
  1084.         case 'pre ':
  1085.             *(long *)info = (long)(*hWE)->tsmPreUpdate;
  1086.             return noErr;
  1087.         
  1088.         case 'refc':
  1089.             *(long *)info = (*hWE)->refCon;
  1090.             return noErr;
  1091.         
  1092.         case 'runa':
  1093.             *(long *)info = (long)(*hWE)->hRuns;
  1094.             return noErr;
  1095.         
  1096.         case 'scrl':
  1097.             *(long *)info = (long)(*hWE)->scrollProc;
  1098.             return noErr;
  1099.         
  1100.         case 'styl':
  1101.             *(long *)info = (long)(*hWE)->hStyles;
  1102.             return noErr;
  1103.         
  1104.         case 'text':
  1105.             *(long *)info = (long)(*hWE)->hText;
  1106.             return noErr;
  1107.         
  1108.         case 'tsmd':
  1109.             *(long *)info = (long)(*hWE)->tsmReference;
  1110.             return noErr;
  1111.     }
  1112.     return paramErr;
  1113. }
  1114.  
  1115. pascal OSErr WESetInfo(OSType selector, Ptr info, WEHandle hWE)
  1116. {
  1117.     switch(selector)
  1118.     {
  1119.         case 'clik':
  1120.             (*hWE)->clickLoop = (ProcPtr)*(long *)info;
  1121.             return noErr;
  1122.         
  1123.         case 'line':
  1124.             (*hWE)->hLines = (LineArrayHandle)*(long *)info;
  1125.             return noErr;
  1126.             
  1127.         case 'port':
  1128.             (*hWE)->port = (GrafPtr)*(long *)info;
  1129.             return noErr;
  1130.         
  1131.         case 'post':
  1132.             (*hWE)->tsmPostUpdate = (ProcPtr)*(long *)info;
  1133.             return noErr;
  1134.         
  1135.         case 'pre ':
  1136.             (*hWE)->tsmPreUpdate = (ProcPtr)*(long *)info;
  1137.             return noErr;
  1138.         
  1139.         case 'refc':
  1140.             (*hWE)->refCon = *(long *)info;
  1141.             return noErr;
  1142.         
  1143.         case 'runa':
  1144.             (*hWE)->hRuns = (RunArrayHandle)*(long *)info;
  1145.             return noErr;
  1146.         
  1147.         case 'scrl':
  1148.             (*hWE)->scrollProc = (ProcPtr)*(long *)info;
  1149.             return noErr;
  1150.         
  1151.         case 'styl':
  1152.             (*hWE)->hStyles = (StyleTableHandle)*(long *)info;
  1153.             return noErr;
  1154.         
  1155.         case 'text':
  1156.             (*hWE)->hText = (Handle)*(long *)info;
  1157.             return noErr;
  1158.         
  1159.         case 'tsmd':
  1160.             (*hWE)->tsmReference = (TSMDocumentID)*(long *)info;
  1161.             return noErr;
  1162.     }
  1163.  
  1164.     return paramErr;
  1165. }
  1166.